#ifndef __SCM_CLOG_H__
#define __SCM_CLOG_H__

#include <stdio.h>
#include <time.h>

/* printf colour for shell */
#define NONE_C       "\033[0m"
#define RED          "\033[0;32;31m"
#define LIGHT_RED    "\033[1;31m"
#define GREEN        "\033[0;32;32m"
#define LIGHT_GREEN  "\033[1;32m"
#define BLUE         "\033[0;32;34m"
#define LIGHT_BLUE   "\033[1;34m"
#define DARY_GRAY    "\033[1;30m"
#define CYAN         "\033[0;36m"
#define LIGHT_CYAN   "\033[1;36m"
#define PURPLE       "\033[0;35m"
#define LIGHT_PURPLE "\033[1;35m"
#define BROWN        "\033[0;33m"
#define YELLOW       "\033[1;33m"
#define LIGHT_GRAY   "\033[0;37m"
#define WHITE        "\033[1;37m"

/* log level number */
enum {
	CLOG_LEVEL_DEBUG = 0,
	CLOG_LEVEL_INFO,
	CLOG_LEVEL_WARN,
	CLOG_LEVEL_ERROR,
	CLOG_LEVEL_MAX,
};
static const char *level_str[] = {
	"debug",
	"info",
	"warn",
	"error",
};

#define LOG_FMT_STR  "[%04d-%02d-%02d %02d:%02d:%02d][%5s][%s:%s:%d] "

/******** console log print, support color *********************/
#define clog_printf(level,fmt,args...) do{ \
	time_t ttt = time(NULL);		\
	struct tm tm_now; \
	struct tm *ptm = localtime_r(&ttt,&tm_now);	\
	printf(LOG_FMT_STR, \
		ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
		level_str[level], \
		__FILE__, __FUNCTION__, __LINE__ ); \
	printf(fmt,##args); \
}while(0)

#define clog_mprint(module,color,level,fmt,args...) do{ \
	printf("%s",color); \
	if(module[0]) printf("[%s]",module); \
	time_t ttt = time(NULL);		\
	struct tm tm_now; \
	struct tm *ptm = localtime_r(&ttt,&tm_now);	\
	printf(LOG_FMT_STR, \
		ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
		level_str[level], \
		__FILE__, __FUNCTION__, __LINE__ ); \
	printf(fmt,##args); \
	printf("%s",NONE_C); \
}while(0)

#define clog_print(fmt,args...) clog_printf(CLOG_LEVEL_INFO,fmt,##args)
#define clog_println(fmt,args...) clog_printf(CLOG_LEVEL_INFO,fmt,##args);printf("\n")
#define clog_cprint(color,level,fmt,args...) clog_mprint("",color,level,fmt,##args)

#define clog_error(fmt,args...)		clog_cprint(LIGHT_RED,CLOG_LEVEL_ERROR,fmt,##args)
#define clog_warn(fmt,args...)		clog_cprint(YELLOW,CLOG_LEVEL_WARN,fmt,##args)
#define clog_info(fmt,args...)		clog_cprint(LIGHT_GREEN,CLOG_LEVEL_INFO, fmt,##args)
#define clog_debug(fmt,args...)		clog_cprint(WHITE,CLOG_LEVEL_DEBUG,fmt,##args)

#define clog_merror(module,fmt,args...)		clog_mprint(module,LIGHT_RED,CLOG_LEVEL_ERROR,fmt,##args)
#define clog_mwarn(module,fmt,args...)		clog_mprint(module,YELLOW,CLOG_LEVEL_WARN,fmt,##args)
#define clog_minfo(module,fmt,args...)		clog_mprint(module,LIGHT_GREEN,CLOG_LEVEL_INFO, fmt,##args)
#define clog_mdebug(module,fmt,args...)		clog_mprint(module,WHITE,CLOG_LEVEL_DEBUG,fmt,##args)

/******** log file write *********************/
#ifdef _CLOG_USE_GLOBAL_FP

extern FILE *g_clog_fp; // 调用者打开全局日志文件句柄,优先使用全局句柄
extern int g_clog_level; // 命名不同从而可以随时开关_CLOG_USE_GLOBAL_FP宏而不冲突

#define clog_open(logfile, mode) do{ \
	printf("\t\t@@@(global logfile)@@@\n"); \
	g_clog_fp = fopen(logfile,mode); \
}while(0)

#define clog_close() do{ \
	if(g_clog_fp!=NULL) { fclose(g_clog_fp);} \
}while(0)

#define clog_mfprint(module,level,fmt,args...) do{ \
	if(g_clog_fp!=NULL && (level) >= g_clog_level) {\
		if(module[0]) fprintf(g_clog_fp,"[%s]",module); \
		time_t ttt = time(NULL);		\
		struct tm tm_now; \
		struct tm *ptm = localtime_r(&ttt,&tm_now);	\
		fprintf(g_clog_fp, LOG_FMT_STR, \
			ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
			level_str[level], \
			__FILE__, __FUNCTION__, __LINE__ ); \
		fprintf(g_clog_fp,fmt,##args); \
	} else { \
		if(module[0]) fprintf(stdout,"[%s]",module); \
		time_t ttt = time(NULL);		\
		struct tm tm_now; \
		struct tm *ptm = localtime_r(&ttt,&tm_now);	\
		printf(LOG_FMT_STR, \
			ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
			level_str[level], \
			__FILE__, __FUNCTION__, __LINE__ ); \
		printf(fmt,##args); \
	} \
}while(0)

#define clog_set_level(level) g_clog_level=level

#elif defined(_CLOG_USE_LOCAL_FP) // 单文件日志记录,每一个源文件均需要调用clog_open来获取文件句柄,除非实现clog.c

static FILE *s_clog_fp = NULL;
static int s_clog_level = CLOG_LEVEL_WARN; // default only warn level log to file
#define clog_open(logfile, mode) do{ \
	printf("\t\t@@@(local logfile)@@@\n"); \
	s_clog_fp = fopen(logfile, mode); \
}while(0)

#define clog_close() do{ \
	if(s_clog_fp!=NULL) { fclose(s_clog_fp);} \
}while(0)

#define clog_mfprint(module,level,fmt,args...) do{ \
	if(s_clog_fp!=NULL && (level) >= s_clog_level) { \
		if(module[0]) fprintf(s_clog_fp,"[%s]",module); \
		time_t ttt = time(NULL);		\
		struct tm tm_now; \
		struct tm *ptm = localtime_r(&ttt,&tm_now);	\
		fprintf(s_clog_fp, LOG_FMT_STR, \
			ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
			level_str[level], \
			__FILE__, __FUNCTION__, __LINE__ ); \
		fprintf(s_clog_fp,fmt,##args); \
	} else { \
		if(module[0]) fprintf(stdout,"[%s]",module); \
		time_t ttt = time(NULL);		\
		struct tm tm_now; \
		struct tm *ptm = localtime_r(&ttt,&tm_now);	\
		printf(LOG_FMT_STR, \
			ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
			level_str[level], \
			__FILE__, __FUNCTION__, __LINE__ ); \
		printf(fmt,##args); \
	} \
}while(0)

#define clog_set_level(level) s_clog_level=level

#else  // 不开启文件宏也可以使用接口,避免注释处理

#define clog_open(file,mode) do{printf("\t\t@@@(only stdout)@@@\n");}while(0)
#define clog_close()         do{}while(0)
#define clog_set_level(level) do{}while(0)

#define clog_mfprint(module,level,fmt,args...) do{ \
	if(module[0]) fprintf(stdout,"[%s]",module); \
	time_t ttt = time(NULL);		\
	struct tm tm_now; \
	struct tm *ptm = localtime_r(&ttt,&tm_now);	\
	printf(LOG_FMT_STR, \
		ptm->tm_year+1900, ptm->tm_mon +1, ptm->tm_mday, ptm->tm_hour, ptm->tm_min, ptm->tm_sec, \
		level_str[level], \
		__FILE__, __FUNCTION__, __LINE__ ); \
	printf(fmt,##args); \
}while(0)

#endif

#define clog_fprint(level,fmt,args...) clog_mfprint("",level,fmt,##args)

#define clog_errorf(fmt,args...)		clog_fprint(CLOG_LEVEL_ERROR,fmt,##args)
#define clog_warnf(fmt,args...)			clog_fprint(CLOG_LEVEL_WARN,fmt,##args)
#define clog_infof(fmt,args...)			clog_fprint(CLOG_LEVEL_INFO,fmt,##args)
#define clog_debugf(fmt,args...)		clog_fprint(CLOG_LEVEL_DEBUG,fmt,##args)

#define clog_merrorf(module,fmt,args...)		clog_mfprint(module,CLOG_LEVEL_ERROR,fmt,##args)
#define clog_mwarnf(module,fmt,args...)			clog_mfprint(module,CLOG_LEVEL_WARN,fmt,##args)
#define clog_minfof(module,fmt,args...)			clog_mfprint(module,CLOG_LEVEL_INFO,fmt,##args)
#define clog_mdebugf(module,fmt,args...)		clog_mfprint(module,CLOG_LEVEL_DEBUG,fmt,##args)

#define clog_hexdump(prefix,data,len,nrow) do{ \
	printf("::%s::\n",prefix); \
	int i = 0, j = 0; \
	for(i=0;i<len;i++) { \
		printf("%02x ", (unsigned char)data[i]); \
		if((i+1) % nrow == 0) printf("\n"); \
	} \
	printf("\n\n"); \
}while(0)

#endif

